#include <crt_wstr.h>
#include <crt_memory.h>

wchar_t* s_wstrcpy(
	wchar_t * dst,
	size_t size,
	 wchar_t const* src)
{

	rc_assert(dst != NULL, NULL)
	rc_assert(src != NULL, NULL)
	rc_assert(size > 1, NULL)

	wchar_t* p1 = dst;
	wchar_t const* p2 = src;

	size_t available = size - 1;
	while ((*p1++ = *p2++) != 0 && --available > 0)
	{

	}
	return( dst );
}


wchar_t* s_wstrncpy(
	wchar_t * dest,
	const wchar_t * source,
	size_t count
)
{
	wchar_t *start = dest;

	while (count && (*dest++ = *source++))    /* copy string */
		count--;

	if (count)                              /* pad out with zeroes */
		while (--count)
			*dest++ = L'\0';

	return(start);
}

wchar_t* s_wstrcat(
	wchar_t * dst,
	size_t size,
	const wchar_t * src
)
{
    s_wstrcpy (dst + s_wstrlen (dst), size, src);
    return dst;
}

wchar_t*  s_wstrncat(
	wchar_t * front,
	const wchar_t * back,
	size_t count
)
{
    wchar_t *ret = front;

    /* Find the end of dest.  */
    front += s_wstrlen (front);

    size_t ds = s_wstrnlen (back, count);

    front[ds] = L'\0';
    s_wmemcpy (front, back, ds);

    return ret;
}


int s_wstrcmp(
	const wchar_t * src,
	const wchar_t * dst
)
{
	int ret = 0;

	while (!(ret = (int)(*src - *dst)) && *dst)
        (void)(++src), ++dst;

	if (ret < 0)
		ret = -1;
	else if (ret > 0)
		ret = 1;

	return(ret);
}

int s_wstricmp(
	const wchar_t * dst,
	const wchar_t * src
)
{
	wchar_t f, l;
	do {
		f = __ascii_towlower(*dst);
		l = __ascii_towlower(*src);
		dst++;
		src++;
	} while ((f) && (f == l));
	return (int)(f - l);
}

int s_wstrcasecmp(
	const wchar_t * dst,
	const wchar_t * src
)
{
	wchar_t f, l;
	do {
		f = __ascii_towlower(*dst);
		l = __ascii_towlower(*src);
		dst++;
		src++;
	} while ((f) && (f == l));
	return (int)(f - l);
}

int s_wstrncmp(
	const wchar_t * first,
	const wchar_t * last,
	size_t count
)
{
	wchar_t f, l;
	int result = 0;
	if (count)
	{
		do {
			f = __ascii_towlower(*first);
			l = __ascii_towlower(*last);
			first++;
			last++;
		} while ((--count) && f && (f == l));

		result = (int)(f - l);
	}
	return result;
}

wchar_t* s_wstrchr(
	const wchar_t * string,
	wchar_t ch
)
{
	while (*string && *string != (wchar_t)ch)
		string++;

	if (*string == (wchar_t)ch)
		return((wchar_t *)string);
	return(NULL);
}

wchar_t*  s_wstrrchr(
	const wchar_t * string,
	wchar_t ch
)
{
	wchar_t *start = (wchar_t *)string;

	while (*string++)                       /* find end of string */
		;
	/* search towards front */
	while (--string != start && *string != (wchar_t)ch)
		;

	if (*string == (wchar_t)ch)             /* wchar_t found ? */
		return((wchar_t *)string);

	return(NULL);
}

size_t s_wstrspn(
	const wchar_t* string,
	const wchar_t* control
)
{
	wchar_t *str = (wchar_t *)string;
	wchar_t *ctl;

	/* 1st char not in control string stops search */
	while (*str) {
		for (ctl = (wchar_t *)control; *ctl != *str; ctl++) {
			if (*ctl == (wchar_t)0) {
				/*
				 * reached end of control string without finding a match
				 */
				return (size_t)(str - string);
			}
		}
		str++;
	}
	/*
	 * The whole string consisted of characters from control
	 */
	return (size_t)(str - string);
}

size_t s_wstrcspn(
	const wchar_t * string,
	const wchar_t * control
)
{
	wchar_t *str = (wchar_t *)string;
	wchar_t *wcset;

	/* 1st char in control string stops search */
	while (*str) {
		for (wcset = (wchar_t *)control; *wcset; wcset++) {
			if (*wcset == *str) {
				return (size_t)(str - string);
			}
		}
		str++;
	}
	return (size_t)(str - string);
}

wchar_t* s_wstrpbrk(
	const wchar_t * string,
	const wchar_t * control
)
{
	wchar_t *wcset;

	/* 1st char in control string stops search */
	while (*string) {
		for (wcset = (wchar_t *)control; *wcset; wcset++) {
			if (*wcset == *string) {
				return (wchar_t *)string;
			}
		}
		string++;
	}
	return NULL;
}


wchar_t* s_wstrstr(
	const wchar_t * wcs1,
	const wchar_t * wcs2
)
{
	wchar_t *cp = (wchar_t *)wcs1;
	wchar_t *s1, *s2;

	if (!*wcs2)
		return (wchar_t *)wcs1;

	while (*cp)
	{
		s1 = cp;
		s2 = (wchar_t *)wcs2;

		while (*s1 && *s2 && !(*s1 - *s2))
            (void)(s1++), s2++;

		if (!*s2)
			return(cp);

		cp++;
	}

	return(NULL);
}


size_t s_wstrlen(
	const wchar_t * wcs
)
{
	size_t len = 0;

	while (wcs[len] != L'\0')
	{
		if (wcs[++len] == L'\0')
			return len;
		if (wcs[++len] == L'\0')
			return len;
		if (wcs[++len] == L'\0')
			return len;
		++len;
	}

	return len;
}

size_t s_wstrnlen (
        const wchar_t *s,
        size_t maxlen
)
{
    const wchar_t *ret = s_wmemchr (s, L'\0', maxlen);
    if (ret)
        maxlen = ret - s;
    return maxlen;
}

wchar_t* s_wstrtok(
	wchar_t * string,
	const wchar_t * control,
	wchar_t ** context
)
{
	wchar_t *token;
	const wchar_t *ctl;

	/* If string==NULL, continue with previous string */
	if (!string)
		string = *context;

	/* Find beginning of token (skip over leading delimiters). Note that
	 * there is no token iff this loop sets string to point to the terminal
	 * null (*string == '\0') */

	while (*string) {
		for (ctl = control; *ctl && *ctl != *string; ctl++)
			;
		if (!*ctl) break;
		string++;
	}

	token = string;

	/* Find the end of the token. If it is not the end of the string,
	 * put a null there. */
	for (; *string; string++) {
		for (ctl = control; *ctl && *ctl != *string; ctl++)
			;
		if (*ctl) {
			*string++ = '\0';
			break;
		}
	}

	/* Update nextoken (or the corresponding field in the per-thread data
	 * structure */
	*context = string;

	/* Determine if a token has been found. */
	if (token == string)
		return NULL;
	else
		return token;
}

wchar_t* s_wstrset(
	wchar_t * string,
	wchar_t val
)
{
	wchar_t *start = string;

	while (*string)
		*string++ = (wchar_t)val;

	return(start);
}


wchar_t* s_wstrrev(
	wchar_t * string
)
{
	wchar_t *start = string;
	wchar_t *left = string;
	wchar_t ch;

	while (*string++)                 /* find end of string */
		;
	string -= 2;

	while (left < string)
	{
		ch = *left;
		*left++ = *string;
		*string-- = ch;
	}

	return(start);
}




